package hn.cch.grammar.io;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;
import java.util.zip.Adler32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipFileUtil {

    private final static Logger logger = Logger.getLogger(ZipFileUtil.class.getName());

    /**
     * 压缩文件
     *
     * @param zipFile  压缩文件
     * @param fileList 文件列表
     * @param rootPath 压缩包内文件路径
     */
    public static void compressZip(File zipFile, List<File> fileList, String rootPath) {


        try (FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
             CheckedOutputStream checkedOutputStream = new CheckedOutputStream(fileOutputStream, new Adler32());
             ZipOutputStream zipOutputStream = new ZipOutputStream(checkedOutputStream)) {
            // 压缩文件包
            for (File file : fileList) {
                compressFile(zipOutputStream, file, rootPath);
            }
            zipOutputStream.finish();
        } catch (IOException e) {
            logger.severe(e.getMessage());
        }
    }

    /**
     * 压缩文件
     *
     * @param zipOutputStream
     * @param file
     * @param path
     * @throws IOException
     */
    public static void compressFile(ZipOutputStream zipOutputStream, File file, String path) throws IOException {
        String filePath = path.trim().length() == 0 ? file.getName() : String.format("%s/%s", path, file.getName());
        if (file.isDirectory()) {
            File[] listFiles = file.listFiles();
            for (int i = 0; i < Objects.requireNonNull(listFiles).length; i++) {
                compressFile(zipOutputStream, listFiles[i], filePath);
            }
        } else {
            zipOutputStream.putNextEntry(new ZipEntry(filePath));
            // 读取单个文件写到压缩包中
            byte[] data = Files.readAllBytes(file.toPath());
            zipOutputStream.write(data, 0, data.length);
            zipOutputStream.closeEntry();
        }
    }

    /**
     * 提取
     *
     * @param zipFile  压缩文件
     * @param savePath 保存路径
     * @return 返回文件列表
     */
    public static List<File> extract(File zipFile, String savePath) {
        List<File> fileList = new ArrayList<>();
        try (FileInputStream fileInputStream = new FileInputStream(zipFile);
             ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) {
            ZipEntry zipEntry = null;
            byte[] byteArray = new byte[1024];
            int size = 0;
            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                File file = new File(savePath, zipEntry.getName());
                if (!file.exists()) {
                    File fileDir = file.getParentFile();
                    logger.warning(String.format("mkdirs:%s", fileDir.mkdirs()));
                }
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                // 写入本地文件
                while ((size = zipInputStream.read(byteArray)) != -1) {
                    fileOutputStream.write(byteArray, 0, size);
                }
                fileOutputStream.close();
                fileList.add(file);
            }
        } catch (IOException e) {
            logger.severe(e.getMessage());
        }
        return fileList;
    }


    /**
     * 获取压缩文件元素
     *
     * @param zipFile 压缩文件
     * @return 文件列表
     */
    public List<ZipEntry> getZipEntryList(ZipFile zipFile) {
        List<ZipEntry> zipEntryList = new ArrayList<>();
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()) {
            ZipEntry zipEntry = entries.nextElement();
            zipEntryList.add(zipEntry);
        }
        return zipEntryList;
    }

}
